const models=require('../models/models');
const path=require('path');
const fs=require('fs')
const captchapng=require('captchapng')
const iconvLite=require('iconv-lite')  //GBK编码转UTF8编码工具

let getFile=(ctx) => {  //封装获取 上传音乐表单的信息和文件，用于增加音乐和编辑音乐
    let {id,title,time,singer,uid}=ctx.request.body;
    let file=ctx.request.files.file;
    let filePath=file.path;
    let lrc=ctx.request.files.lrc;
    let lrcPath=lrc.path;
    //下面判断必须项不能为空，
    if(!id||!title||!uid){
        ctx.throw('必填有空项');  //响应体抛错
    }
    let musicFile='';
    let musicLrc='';
    let time1=Date.now()+'';
    if(!file.name){   //文件判断是否为空找name属性，没传文件也会给一个对象
        //上传文件为空，要判断是否有oldfile接收到，因为我在编辑文件页面，假如用户不修改音乐文件
        //只修改音乐信息不更新文件，那么oldfile我在前台设置了原音乐文件路径，就会赋值给musicFile存到数据库
        if (!ctx.request.body.oldfile) {
            ctx.throw('必填有空项');  //响应体抛错
        }
        //koa-formidable控件使得客户端没上传文件也会得到一个无意义空文件，下面就是删除文件
        fs.unlink(filePath, (err) => {
            if(err)console.log(err);
        });
        musicFile=ctx.request.body.oldfile;

    }else{  //如果上传音乐文件不为空，就两种情况，一种是新增音乐文件，一种是编辑更改文件
        musicFile='/public/upload/'+time1+path.extname(filePath);  //将文件以上传目录+时间截命名传入数据库
        //下面两句是node改本地文件名方式
        let newPath=path.join(path.dirname(filePath),time1)+path.extname(filePath);
        fs.rename(filePath,newPath,(err)=>{
            if(err)console.log(err)
        });

    }
    if(!lrc.name){
        musicLrc=ctx.request.body.oldlrc;
        fs.unlink(lrcPath, (err) => {
            console.log(lrcPath);
            if(err)console.log(err);
        });
    }else{
        musicLrc='/public/upload/'+time1+path.extname(lrcPath);  //lrc歌词文件同上原来
        let newLrcName=path.join(path.dirname(lrcPath),time1)+path.extname(lrcPath);
        fs.rename(lrcPath,newLrcName,function (err) {
            if(err)console.log(err);
        })
    }
    return {id,title,time,singer,uid,musicFile,musicLrc}  //返回获取的表单数据，下面调用就拿到存数据库

}
//此模块为控制器，主要处理逻辑、引入model模型db数据、render渲染，
//至于model模型是对各种数据处理，例如各种数据库处理
module.exports={
    showRegister:async (ctx)=>{
        ctx.render('register');
    },
    showIndex:async (ctx) => {
        //打开首页如果session里没有用户对象，即没登录存用户数据对象进去，就跳到登录页面
        if(!ctx.session.user)ctx.redirect('/login')
        const {uid}=ctx.session.user; //有用户对象在session获取对象uid
        let results=await models.musicList(uid); //用uid去models模型数据查询，获得音乐数据
        ctx.render('index',{results})
    },
    showAdd:async (ctx) => {
        ctx.render('add')
    },
    editMusic:async (ctx) => {
        let results=await models.findMusic(ctx.request.query.mid);
        ctx.render('edit',{results:results[0]})
    },
    showLogin:async (ctx) => {
        ctx.render('login',{hide:'hide'})
    },
    getUser:async (ctx) => {
        let {username}=ctx.request.query; //拿到前台传来user
        let users=await models.findUsers(username);
        if (users.length===0){
            ctx.body={code:'001',msg:username+'可以注册'};
        }else{ctx.body={code:'002',msg:username+'已被注册'}}
    },
    doRegister:async (ctx) => {
        let {username,password,email,vcode}=ctx.request.body;
        if (ctx.session.vcode!==vcode){
            ctx.body={code:'003',msg:'验证码错误'};
            return
        }
        let users=await models.findUsers(username);
        if (users.length!==0){
            ctx.response.body={code:'002',msg:username+'已被注册'}
            return
        }
        //开始注册
        try{    //读数据库可能会出现错误，所以这些异步操作要预防抛错
            let results=await models.insertRegister(
                username,password,email,vcode
            )
            if (results.affectedRows===1){ctx.response.body={code:'001',msg:'注册成功'}} else{
                ctx.response.body={code:'002',msg:'注册失败'}
            }
        }catch(err){
            ctx.throw(err)
        }

    },
    toLogin:async (ctx) => {
        let {username,password}=ctx.request.body;
        let results=await models.findUsers(username)
        if (results.length===0)ctx.throw('用户名或密码错误');
        if(results[0].password===password){
            //登录成功将数据库用户数据对象存到session，注意后台取session也是对象，前端html取是字符串
            ctx.session.user=results[0] ;
            ctx.set('Content-Type','text/html;charset=utf-8')
            ctx.body='<h3>登录成功，即将跳转到首页<span id="f3">3</span></h3>' +
                '<script>' +
                'var i=2;'+
                'var start1=setInterval(function() { document.getElementById("f3").innerText=i;if(i===0){clearInterval(start1);window.location.href="/"};i--;},1000);' +
                '</script>'
        }else{
            ctx.throw('用户名或密码错误');
        }


    },
    addMusic:async (ctx) => {
        let {id,title,time,singer,uid,musicFile,musicLrc}=getFile(ctx);
        let results=await models.addMusic(id,title,time,singer,uid,musicFile,musicLrc);
        if (results.affectedRows===1){  //是否添加成功，就看这个属性是不是大于0，一般插入一条都是1
            ctx.body={code:'001',msg:'成功添加音乐'}
        }else{
            ctx.body={code:'002',msg:results.message}
        }
    },
    updateMusic:async (ctx) => {
        let {id,title,time,singer,uid,musicFile,musicLrc}=getFile(ctx);
        const {mid}=ctx.request.body;
        let results=await models.updateMusic(mid,id,title,time,singer,uid,musicFile,musicLrc);
        ctx.redirect('/')
    },
    getVerify:async (ctx) => {
    //用工具生成验证码，可以看javascript比较用canvas制作验证码更复杂
    let rand=parseInt(Math.random()*9000+1000);
    //后台这code码要用session传cookie中，让doRegister组件接收表单中的vcode和cookie的session.vcode对比
    ctx.session.vcode=rand+'';

    let p = new captchapng(80,30,rand); //随机四个数字验证码，80长30宽
    p.color(0, 0, 0, 0);  // 背景颜色
        p.color(32, 3, 2, 255); // 字体颜色
        let img = p.getBase64();

        var imgbase64 = Buffer.from(img,'base64');
        ctx.status=200;
        ctx.set('Content-Type','image/png')
        ctx.body=imgbase64;
    },
    delMusic:async (ctx) => {
        let mid=ctx.query.mid;
        let results=await models.delMusic(mid)
        if(results.affectedRows!==1)ctx.throw({code:'002',msg:'删除失败，检查语法'})
        ctx.body={code:'001',msg:'删除成功'}
    },
    quitLogout:async (ctx)=>{
        ctx.session.user='';
        ctx.redirect('/login')
    },
    getLrc:async (ctx) => {
        const lrcName=ctx.request.query.lrc
        let lrcStr=fs.readFileSync(path.resolve('./public/upload/'+lrcName))
        lrcStr=iconvLite.decode(lrcStr,'gbk')  //iconvLite.decode方法是GBK编码转UTF8编码
        console.log(lrcStr);
        ctx.body={code:'001',lrcStr}
    }

}